-module(s1_sub).
-hehaviour(gen_server).
-export([start/0,start_link/1,start/1,init/1,handle_call/3,handle_cast/2,handle_info/2,terminate/2,code_change/3]).
-export([handle/2,cast/2]).
-include("protocol.hrl").
-include("nas.hrl").
-include("S1AP.hrl").
-include("subscriber.hrl").

%%refer to spec 24.301

-define(SERVER,?MODULE).
-record(s1_sub_sta,{
	state,
	sub_pid = undefined,
	nodeb_sid
}).
handle(Pid,Message) ->
  try
	  gen_server:call(Pid,Message),
    ok
  catch
    _M:_Reason ->
      error
  end.
cast(Pid,Message) ->
	gen_server:cast(Pid,Message).
start()  ->
	gen_server:start(?MODULE, [], []).
start(Ue_Id)  ->
	gen_server:start(?MODULE, [Ue_Id], []).
start_link(Ue_Id) ->
	gen_server:start_link(?MODULE, [Ue_Id], []).

init(Ue_Id) ->
  process_flag(trap_exit, false),
	{ok,{running,#s1_sub_sta{state=initialing,sub_pid=undefined,nodeb_sid = Ue_Id}}}.

handle_call({packet_comming,S1Ap_Nas},_,{running,Sta}) when (S1Ap_Nas#s1ap_nas.s1ap_proc =:= ?'id-initialUEMessage')
															and (S1Ap_Nas#s1ap_nas.tmsi =/= undefined) ->
	try
		{_,Tmsi} = S1Ap_Nas#s1ap_nas.tmsi,
		{ok,Pid} = subscriber_sup:create({tmsi,Tmsi},#sub_lte{tmsi=(Tmsi)},[associate,subscriber_lte]),
		gen_server:call(Pid,{rrc_connect,establish,S1Ap_Nas}),
		gen_server:call(Pid,{nas_msg,S1Ap_Nas}),
		{reply,ok,{running,Sta#s1_sub_sta{sub_pid = Pid}}}
	catch
		true ->
      io:format("s1 session abnormal terminted by ~p~n",[S1Ap_Nas]),
			{stop,abnormal,Sta}
	end;

handle_call({packet_comming,S1Ap_Nas},_,{running,Sta}) when (S1Ap_Nas#s1ap_nas.s1ap_proc =:= ?'id-initialUEMessage')
															and (S1Ap_Nas#s1ap_nas.tmsi =:= undefined) ->
	Pid = subscriber_sup:create(#sub_lte{},[subscriber_lte]),
  gen_server:call(Pid,{rrc_connect,establish,S1Ap_Nas}),
	%%create a nonymous subscriber to analysis
	gen_server:call(Pid,{nas_msg,S1Ap_Nas}),
	{reply,ok,{running,Sta#s1_sub_sta{sub_pid = Pid}}};

handle_call({packet_comming,S1Ap_Nas},_,{running,Sta}) when (S1Ap_Nas#s1ap_nas.s1ap_proc =:= ?'id-ErrorIndication')
															and (Sta#s1_sub_sta.sub_pid /= undefined) ->
  gen_server:call(Sta#s1_sub_sta.sub_pid,{rrc_connect,release,S1Ap_Nas}),
  {stop,normal,Sta#s1_sub_sta{sub_pid = undefined}};


handle_call({packet_comming,S1Ap_Nas},_,{running,Sta}) when is_record(S1Ap_Nas,s1ap_nas) and
															(Sta#s1_sub_sta.sub_pid /= undefined) ->
	gen_server:call(Sta#s1_sub_sta.sub_pid,{nas_msg,S1Ap_Nas}),
	{reply,ok,{running,Sta}};

handle_call({packet_comming,S1Ap_Nas},_,{running,Sta}) when is_record(S1Ap_Nas,s1ap_nas) and
															(Sta#s1_sub_sta.sub_pid =:= undefined) ->
	io:format("unmatch session ~n"),
	{reply,ok,{running,Sta}};

handle_call({packet_comming,S1Ap_Nas},_,{running,Sta}) ->
	%%io:format("ignore message ~p in sta:~p~n",[S1Ap_Nas,Sta]),
	{reply,ok,Sta};
handle_call(dump,_,State) ->
	io:format("s1_st:~n~p~n",[State]),
	{reply,ok,State};
handle_call(Msg,_,State) ->
	%%io:format("unknow message ~p at state ~p ~n",[Msg,State]),
	{reply, {error,"S1sub:no func defined"}, State}.

handle_cast({reset,S1Ap_Nas},{running,Sta}) when  Sta#s1_sub_sta.sub_pid =/= undefined ->
	gen_server:call(Sta#s1_sub_sta.sub_pid,{rrc_connect,reset}),
  {stop,normal,Sta#s1_sub_sta{sub_pid = undefined}};

handle_cast({release,S1Ap_Nas},{running,Sta}) when  Sta#s1_sub_sta.sub_pid =/= undefined ->
	gen_server:call(Sta#s1_sub_sta.sub_pid,{rrc_connect,release,S1Ap_Nas}),
	{stop,normal,Sta#s1_sub_sta{sub_pid = undefined}};

handle_cast(Request, State) ->
	%%error_logger:format("unkown request received~p at sta:~p ~n",[Request,State]),
	{noreply,State}.

handle_info(_, State) ->
	{noreply,State}.

terminate(_,State) when State#s1_sub_sta.sub_pid =/= undefined ->
  try
	  gen_server:call(State#s1_sub_sta.sub_pid,{rrc_connect,force_down})
  catch
    M:Reason ->
      io:format("no child process ~p ~p ~n",[M,Reason])
  end,
	ok;

terminate(_,State) when State#s1_sub_sta.sub_pid =:= undefined ->
  %%io:format("terminted with ~p ~n",[State]),
	ok.

code_change(_, State, _) ->
	{ok,State}.
